package com.nulldev.util.settings;

import java.io.File;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;

import com.nulldev.util.io.FileUtil;
import com.nulldev.util.java.JVMUtil;
import com.nulldev.util.logging.Logger;
import com.nulldev.util.logging.LoggerFactory;
import com.nulldev.util.math.MathUtil;
import com.nulldev.util.other.ArrayUtils;
import com.nulldev.util.string.StringsUtil;
import com.nulldev.util.uri.URIUtil;

public class FormattedDataFile {

	public static final String DEFAULT_VALUE = "value.default";
	public static final String HOME_DIRECTORY = System.getProperty("user.home");
	private static final Logger log = LoggerFactory.getLogger(true, true);
	
	private String[] data = new String[0];
	public FormattedDataFile(final File location) throws Exception {
		if (!location.exists()) {
			//location.createNewFile();
			//FileUtil.writeFile(location, "<FDF level=1><newline>");
			throw new UnsupportedOperationException("File not found!");
		}
		if (!FileUtil.getFileExtension(location).equals("fdf") 
				&& !FileUtil.getFileExtension(location).equals("pcmec")
				&& !FileUtil.getFileExtension(location).equals("nmc")
				&& !FileUtil.getFileExtension(location).equals("ftf")) {
			throw new UnsupportedOperationException("Unsupported file!");
		}
		final String line0 = FileUtil.readFirstLine(location).split("<newline>")[0];
		if (line0.startsWith("<") && line0.endsWith(">")) {
			final String[] dta = line0.substring(1, line0.length() - 1).split(" ");
			if (StringsUtil.isEqualCM(dta, 0, "FDF")) {
				final int level = MathUtil.safeParseI(dta[1].split("=")[1], 1);
				log.debug("Reading an FDF file with API level '" + level + "'.");
				this.type = FDF_Type.FDF;
			}else if (StringsUtil.isEqualCM(dta, 0, "PCMEC")) {
				final int level = MathUtil.safeParseI(dta[1].split("=")[1], 1);
				log.debug("Reading an PCMEC file with API level '" + level + "'.");
				this.type = FDF_Type.PCMEC;
			}else if (StringsUtil.isEqualCM(dta, 0, "NMC")) {
				final int level = MathUtil.safeParseI(dta[1].split("=")[1], 1);
				log.debug("Reading an NMC file with API level '" + level + "'.");
				this.type = FDF_Type.NMC;
			}
			this.data = FileUtil.readFileToString(location).split("<newline>");
		}else {
			throw new UnsupportedOperationException("Unsupported file format!");
		}
	}
	
	public FormattedDataFile(final URL location) throws Exception {
		final String line0 = URIUtil.downloadPage(location).split("<newline>")[0];
		if (line0.startsWith("<") && line0.endsWith(">")) {
			final String[] dta = line0.substring(1, line0.length() - 1).split(" ");
			if (StringsUtil.isEqualCM(dta, 0, "FDF")) {
				final int level = MathUtil.safeParseI(dta[1].split("=")[1], 1);
				log.debug("Reading an FDF file with API level '" + level + "'.");
				this.type = FDF_Type.FDF;
			}else if (StringsUtil.isEqualCM(dta, 0, "PCMEC")) {
				final int level = MathUtil.safeParseI(dta[1].split("=")[1], 1);
				log.debug("Reading an PCMEC file with API level '" + level + "'.");
				this.type = FDF_Type.PCMEC;
			}else if (StringsUtil.isEqualCM(dta, 0, "NMC")) {
				final int level = MathUtil.safeParseI(dta[1].split("=")[1], 1);
				log.debug("Reading an NMC file with API level '" + level + "'.");
				this.type = FDF_Type.NMC;
			}else if (StringsUtil.isEqualCM(dta, 0, "FTF")) {
				final int level = MathUtil.safeParseI(dta[1].split("=")[1], 1);
				log.debug("Reading an FTF file with API level '" + level + "'.");
				this.type = FDF_Type.NMC;
			}
			this.data = URIUtil.downloadPage(location).split("<newline>");
		}else {
			throw new UnsupportedOperationException("Unsupported file format!");
		}
	}
	
	public HashMap<String, String> getSection(final String section){
		if (!isSection(section)) {
			return new HashMap<String, String>();
		}
		final HashMap<String, String> out = new HashMap<String, String>(0);
		boolean expectedEOF = false;
		for (int i = 0; i < this.data.length; i++) {
			final String dta = this.data[i].replaceAll(JVMUtil.LINE_SEP_WINDOWS, "").replaceAll(JVMUtil.LINE_SEP_BASIC, "");
			if (dta.startsWith("<") && dta.endsWith(">") && !expectedEOF) {
			}else if (dta.startsWith("</") && dta.endsWith(">") && expectedEOF){
				expectedEOF = false;
			}else if (dta.startsWith("</") && dta.endsWith(">") && !expectedEOF) {
				throw new UnsupportedOperationException("Incorrectly formatted file! [Error at line " + (i + 1) + "]");
			}else {
				final String[] dtax = dta.split(": ");
				out.put(dtax[0], ArrayUtils.StringArrayUtils.addFrom(dtax, 1));
			}
		}
		return out;
	}
	
	public HashMap<String, HashMap<String, String>> readAll() {
		final HashMap<String, HashMap<String, String>> out = new HashMap<String, HashMap<String, String>>();
		final String[] sections = getSections();
		for (final String section : sections) {
			out.put(section, getSection(section));
		}
		return out;
	}
	
	public String[] getSections() {
		final ArrayList<String> out = new ArrayList<String>();
		boolean expectedEOF = false;
		for (int i = 0; i < this.data.length; i++) {
			final String dta = this.data[i].replaceAll(JVMUtil.LINE_SEP_WINDOWS, "").replaceAll(JVMUtil.LINE_SEP_BASIC, "");
			if (dta.startsWith("<") && dta.endsWith(">") && !expectedEOF) {
				expectedEOF = true;
			}else if (dta.startsWith("</") && dta.endsWith(">") && expectedEOF){
				expectedEOF = false;
				out.add(StringsUtil.substringBetween(dta, "</", ">"));
			}else if (dta.startsWith("</") && dta.endsWith(">") && !expectedEOF) {
				throw new UnsupportedOperationException("Incorrectly formatted file! [Error at line " + (i + 1) + "]");
			}
		}
		return ArrayUtils.arrayListToArray(out);
	}
	
	public boolean isSection(final String section) {
		if (this.data == null) {
			return false;
		}
		final ArrayList<String> sections = new ArrayList<String>();
		boolean expectedEOF = false;
		boolean endedWithEOF = false;
		boolean startedSection = false;
		for (int i = 0; i < this.data.length; i++) {
			final String dta = this.data[i].replaceAll(JVMUtil.LINE_SEP_WINDOWS, "").replaceAll(JVMUtil.LINE_SEP_BASIC, "");
			if (dta.startsWith("<") && dta.endsWith(">") && !expectedEOF) {
				endedWithEOF = false;
				expectedEOF = true;
				startedSection = true;
			}else if (dta.startsWith("</") && dta.endsWith(">") && expectedEOF){
				expectedEOF = false;
				sections.add(StringsUtil.substringBetween(dta, "</", ">"));
				endedWithEOF = true;
				startedSection = false;
			}else if (dta.startsWith("</") && dta.endsWith(">") && !expectedEOF) {
				throw new UnsupportedOperationException("Incorrectly formatted file! [Error at line " + (i + 1) + "]");
			}
		}
		if (startedSection && !endedWithEOF) {
			throw new UnsupportedOperationException("Incorrectly formatted file! [Missing an end section declare.]");
		}
		return sections.contains(section);
	}
	
	private FDF_Type type = FDF_Type.FDF.UNKNOWN;
	public static enum FDF_Type {
		UNKNOWN,
		FDF,
		PCMEC,
		NMC,
	}
	
	public FDF_Type getType() {
		return this.type;
	}
}
